geom_violin in ggplot2
How to make a density map using geom_violin. Includes explanations on flipping axes and facetting.
Basic violin plot
A basic violin plot showing how Democratic vote share in the 2018 elections to the US House of Representatives varied by level of density. A horizontal bar is added, to divide candidates who lost from those who won.
Source: Dave Wassermann and Ally Flinn for the election results and CityLab for its Congressional Density Index. Regional classifications are according to the Census Bureau.
library(plotly)
district_density <- read.csv("https://raw.githubusercontent.com/plotly/datasets/master/district_density.csv", stringsAsFactors = FALSE)
district_density$cluster <- factor(district_density$cluster, levels=c("Pure urban", "Urban-suburban mix", "Dense suburban", "Sparse suburban", "Rural-suburban mix", "Pure rural"))
district_density$region <- factor(district_density$region, levels=c("West", "South", "Midwest", "Northeast"))
p <- ggplot(district_density,aes(x=cluster, y=dem_margin, fill=cluster)) +
geom_violin(colour=NA) +
geom_hline(yintercept=0, alpha=0.5) +
labs(title = "Democratic performance in the 2018 House elections, by region and density",
x = "Density Index\nfrom CityLab",
y = "Margin of Victory/Defeat")
ggplotly(p)
Flipping the Axes
With geom_violin(), the y-axis must always be the continuous variable, and the x-axis the categorical variable. To create horizontal violin graphs, keep the x- and y-variables as is and add coord_flip().
library(plotly)
district_density <- read.csv("https://raw.githubusercontent.com/plotly/datasets/master/district_density.csv", stringsAsFactors = FALSE)
district_density$cluster <- factor(district_density$cluster, levels=c("Pure urban", "Urban-suburban mix", "Dense suburban", "Sparse suburban", "Rural-suburban mix", "Pure rural"))
district_density$region <- factor(district_density$region, levels=c("West", "South", "Midwest", "Northeast"))
p <- ggplot(district_density,aes(x=cluster, y=dem_margin, fill=cluster)) +
geom_violin(colour=NA) +
geom_hline(yintercept=0, alpha=0.5) +
labs(title = "Democratic performance in the 2018 House elections, by region and density",
x = "Density Index\nfrom CityLab",
y = "Margin of Victory/Defeat") +
coord_flip()
ggplotly(p)
Add facetting
Including facetting by region.
library(plotly)
district_density <- read.csv("https://raw.githubusercontent.com/plotly/datasets/master/district_density.csv", stringsAsFactors = FALSE)
district_density$cluster <- factor(district_density$cluster, levels=c("Pure urban", "Urban-suburban mix", "Dense suburban", "Sparse suburban", "Rural-suburban mix", "Pure rural"))
district_density$region <- factor(district_density$region, levels=c("West", "South", "Midwest", "Northeast"))
p <- ggplot(district_density,aes(x=cluster, y=dem_margin, fill=cluster)) +
geom_violin(colour=NA) +
geom_hline(yintercept=0, alpha=0.5) +
facet_wrap(~region) +
labs(title = "Democratic performance in the 2018 House elections, by region and density",
x = "Density Index\nfrom CityLab",
y = "Margin of Victory/Defeat") +
coord_flip()
ggplotly(p)
Customized Appearance
Add colour to the facet titles, centre-align the title, rotate the y-axis title, change the font, and get rid of the unnecessary legend. Note that coord_flip() flips the axes for the variables and the titles, but does not flip theme() elements.
library(plotly)
district_density <- read.csv("https://raw.githubusercontent.com/plotly/datasets/master/district_density.csv", stringsAsFactors = FALSE)
district_density$cluster <- factor(district_density$cluster, levels=c("Pure urban", "Urban-suburban mix", "Dense suburban", "Sparse suburban", "Rural-suburban mix", "Pure rural"))
district_density$region <- factor(district_density$region, levels=c("West", "South", "Midwest", "Northeast"))
p <- ggplot(district_density,aes(x=cluster, y=dem_margin, fill=cluster)) +
geom_violin(colour=NA) +
geom_hline(yintercept=0, alpha=0.5) +
facet_wrap(~region) +
labs(title = "Democratic performance in the 2018 House elections, by region and density",
x = "Density Index\nfrom CityLab",
y = "Margin of Victory/Defeat") +
coord_flip() +
theme(axis.title.y = element_text(angle = 0, vjust=0.5),
plot.title = element_text(hjust = 0.5),
strip.background = element_rect(fill="lightblue"),
text = element_text(family = 'Fira Sans'),
legend.position = "none")
ggplotly(p)
Rotated Axis Text
Rotated the x-axis text 45 degrees, and used facet_grid to create a 4x1 facet (compared to facet_wrap, which defaults to 2x2).
library(plotly)
district_density <- read.csv("https://raw.githubusercontent.com/plotly/datasets/master/district_density.csv", stringsAsFactors = FALSE)
district_density$cluster <- factor(district_density$cluster, levels=c("Pure urban", "Urban-suburban mix", "Dense suburban", "Sparse suburban", "Rural-suburban mix", "Pure rural"))
district_density$region <- factor(district_density$region, levels=c("West", "South", "Midwest", "Northeast"))
p <- ggplot(district_density,aes(x=cluster, y=dem_margin, fill=cluster)) +
geom_violin(colour=NA) +
geom_hline(yintercept=0, alpha=0.5) +
facet_grid(.~region) +
labs(title = "Democratic performance in the 2018 House elections, by region and density",
x = "Density Index\nfrom CityLab",
y = "Margin of Victory/Defeat") +
theme(axis.text.x = element_text(angle = -45),
plot.title = element_text(hjust = 0.5),
strip.background = element_rect(fill="lightblue"),
text = element_text(family = 'Fira Sans'),
legend.position = "none")
ggplotly(p)

